/**
 * @(#)CodeEntityThrowRelation.java, 2008-4-30.
 * Copyright 2008  Program Analysis Research Group(PARG),Institute of Software, Peking University.
 * All rights reserved.
 */
package edu.pku.sei.pgie.analyzer.internal.relation;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import edu.pku.sei.pgie.analyzer.internal.CodeEntitySymbolTable;

/**
 * @author HeLi
 */
public class CodeEntityThrowRelation extends AbstractCodeEntityRelation {

	class ThrowVisitor extends ASTVisitor {
		List<String[]> container;

		Stack<String> typeDeclarationStack;

		public List<String[]> getResult() {
			return container;
		}

		public ThrowVisitor() {
			this.container = new ArrayList<String[]>();
			typeDeclarationStack = new Stack<String>();
		}

		public void endVisit(TypeDeclaration node) {
			if (!typeDeclarationStack.isEmpty()) {
				typeDeclarationStack.pop();
			}
		}

		public boolean visit(MethodDeclaration node) {
			List throwExceptions = node.thrownExceptions();
			if (throwExceptions == null)
				return true;
			Iterator iterator = throwExceptions.iterator();
			String typeName = (String) typeDeclarationStack.peek();
			while (iterator.hasNext()) {
				Name exception = (Name) iterator.next();
				IBinding typeBinding = exception.resolveBinding();
				if (typeBinding == null) {
					continue;
				}
				if (typeBinding instanceof ITypeBinding) {
					String fqn = ((ITypeBinding) typeBinding)
							.getQualifiedName();
					container.add(new String[] { typeName, fqn });
				}
			}
			return true;
		}

		public boolean visit(TypeDeclaration node) {
			ITypeBinding typeBinding = node.resolveBinding();
			String fqn = typeBinding.getQualifiedName();
			typeDeclarationStack.push(fqn);
			return true;
		}

	}

	public String[][] collectCallBack(CompilationUnit root,
			CodeEntitySymbolTable symbolTable) throws Exception {
		ThrowVisitor visitor = new ThrowVisitor();
		root.accept(visitor);
		List<String[]> result = visitor.getResult();
		return result.toArray(new String[result.size()][]);
	}
}
